# @Time : 2025-03-11 10:26
# @Author : Fioman 
# @Phone : 13149920693
"""
2拼板的算法,板子横着进来的
"""
import os
import time

from vision_process.calc_config import *
from vision_process.totalboard_check import check_totalboard_is_ok
from vision_process.vision_helper import *

cp = CameraParams()
rp = RobotParams()

tryBeginIndex = 1
# calcArgs = {
#     "1": [[2], 13, 11, 10, 18, [120, 90, 60, 30], 0.2],
#     "2": [[2], 17, 11, 10, 16, [60, 50, 30, 20], 0.3],
#     # "2": [[2], 17, 11, 8, 15, [120, 60, 30, 20], 0],
# }
calcArgs = {
    "1": [[2], 13, 17, 10, 20, [10, 20, 30, 90], 0.2],
    "2": [[2], 17, 17, 10, 20, [10, 60, 90, 120], 0.3],
    # "2": [[2], 17, 11, 8, 15, [120, 60, 30, 20], 0],
}


def find_middle_line(board, edgeLineAngle, splitNumber):
    # 首先是这里中缝找不到了,将这个board分成多个等分,然后每个等分求一个矩形,
    # 然后将求得的矩形和之前的斜率做对比
    # 求出斜率差值最小的那个就是要求的斜率.
    offset = board.shape[1] // splitNumber
    findLineKb = []
    for i in range(splitNumber):
        boardUsed = board[:, offset * i:offset * (i + 1)]
        image_show("BoardUsed_{}".format(i + 1), boardUsed)
        cnts = cv.findContours(boardUsed.copy(), cv.RETR_EXTERNAL,
                               cv.CHAIN_APPROX_SIMPLE)[0]
        cntsSorted = sorted(cnts, key=cv.contourArea, reverse=True)
        if len(cnts) == 0:
            continue
        rectBox = cv.minAreaRect(cntsSorted[0])
        rectBoxPoints = np.intp(cv.boxPoints(rectBox))
        leftTop, rightTop, rightBottom, leftBottom = get_rect_points_clockwise(rectBoxPoints)
        middleError = board.shape[0] - get_two_points_middle(leftBottom, rightBottom)[1]

        print("MiddleError: {}".format(middleError))
        if middleError < 10 * cp.mm2pix:
            continue
        useImage = cv.cvtColor(boardUsed, cv.COLOR_GRAY2BGR)
        cv.drawContours(useImage, [rectBoxPoints], -1, colorGreen, 2)
        image_show("MiddleLineFinded_{}".format(i + 1), useImage)
        findLineKb.append(get_line_k_and_b(leftBottom, rightBottom))

    if len(findLineKb) > 0:
        cv.destroyAllWindows()
        # 按照K和B进行排序,选出和传入的角度出差最小的
        lineKRes = sorted(findLineKb, key=lambda x: abs(edgeLineAngle - get_angle_by_k(x[0])))
        return lineKRes[0]
    else:
        return None


def check_inner_board_1p(board, width, height, boardColor, totalboardBox, tryTime) -> CheckResult:
    result = CheckResult()
    try:
        totalHeightPix, totalWidthPix = board.shape[:2]
        moveWidth13Left = int(totalWidthPix * 0.15)
        moveWidth13Right = int(totalWidthPix * 0.35)
        moveWidthMidLeft = int(totalWidthPix * 0.15)
        moveWidthMidRight = int(totalWidthPix * 0.45)
        moveHeight = int(totalHeightPix * 0.25)
        widthMax = width / cp.mm2pix + calcThresBig
        widthMin = width / cp.mm2pix - calcThresSmall
        heightMax = height / cp.mm2pix + calcThresBig
        heightMin = height / cp.mm2pix - calcThresSmall
        widthMm = width / cp.mm2pix
        heightMm = height / cp.mm2pix

        moveAngleUsed = board.copy()
        firstMoveWay = True
        if firstMoveWay:
            cv.rectangle(moveAngleUsed, (0, 0), (moveWidth13Left, moveHeight), 0, -1)
            cv.rectangle(moveAngleUsed, (moveAngleUsed.shape[1], 0),
                         (moveAngleUsed.shape[1] - moveWidth13Right, moveHeight), 0, -1)
            cv.rectangle(moveAngleUsed, (0, moveAngleUsed.shape[0] - moveHeight),
                         (moveWidthMidLeft, moveAngleUsed.shape[0]), 0, -1)
            cv.rectangle(moveAngleUsed,
                         (moveAngleUsed.shape[1] - moveWidthMidRight, moveAngleUsed.shape[0] - moveHeight),
                         (moveAngleUsed.shape[1], moveAngleUsed.shape[0]), 0, -1)
        else:
            cv.rectangle(moveAngleUsed, (0, 0), (moveWidthMidLeft, moveHeight), 0, -1)
            cv.rectangle(moveAngleUsed, (moveAngleUsed.shape[1], 0),
                         (moveAngleUsed.shape[1] - moveWidthMidRight, moveHeight), 0, -1)
            cv.rectangle(moveAngleUsed, (0, moveAngleUsed.shape[0] - moveHeight),
                         (moveWidth13Left, moveAngleUsed.shape[0]), 0, -1)
            cv.rectangle(moveAngleUsed,
                         (moveAngleUsed.shape[1] - moveWidth13Right, moveAngleUsed.shape[0] - moveHeight),
                         (moveAngleUsed.shape[1], moveAngleUsed.shape[0]), 0, -1)
        image_show("AngleMoved", moveAngleUsed)

        cnts = cv.findContours(moveAngleUsed.copy(), cv.RETR_EXTERNAL,
                               cv.CHAIN_APPROX_SIMPLE)[0]
        cntsSorted = sorted(cnts, key=cv.contourArea, reverse=True)
        if len(cntsSorted) == 0:
            result.state = False
            result.info = f"找内板失败,没有找到任何轮廓"
            return result
        rectBox = cv.minAreaRect(cntsSorted[0])
        rectBoxPoints = np.intp(cv.boxPoints(rectBox))
        leftTop, rightTop, rightBottom, leftBottom = get_rect_points_clockwise(rectBoxPoints)
        edgeLineAngle = get_angle_by_k(get_line_k(leftBottom, rightBottom))
        yOffset = (get_two_points_middle(leftTop, rightTop)[1]) // cp.mm2pix
        print(f" 第三边角度: {edgeLineAngle:.3f},中缝顶部偏移:{yOffset}")
        edgeLineAngle = get_angle_by_k(get_line_k(leftTop, rightTop))
        yOffset = - (get_two_points_middle(leftBottom, rightBottom)[1] - board.shape[0]) // cp.mm2pix
        print(f" 第一边角度: {edgeLineAngle:.3f},第三遍底部偏移 :{yOffset}")
        if abs(edgeLineAngle) > calc_config.angleMax:
            result.state = False
            result.info = f"找内板失败,边线角度大于{calc_config.angleMax}度"
            return result
        middleIsOk = True
        if abs(yOffset) < 10:
            middleIsOk = False
            middleLineKB = find_middle_line(board, edgeLineAngle, 4)
            if middleLineKB is None:
                middleLineKB = find_middle_line(board, edgeLineAngle, 6)
            if middleLineKB is None:
                middleLineKB = find_middle_line(board, edgeLineAngle, splitNumber=8)
            if middleLineKB is not None:
                middleIsOk = True
                middleK, middleB = middleLineKB
                leftK, leftB = get_line_k_and_b(leftTop, leftBottom)
                rightK, rightB = get_line_k_and_b(rightTop, rightBottom)
                leftBottom = get_two_lines_intersection(leftK, leftB, middleK, middleB)
                leftBottom = int(leftBottom[0]), int(leftBottom[1])
                rightBottom = get_two_lines_intersection(rightK, rightB, middleK, middleB)
                rightBottom = int(rightBottom[0]), int(rightBottom[1])
        sizeByExtend = False
        if not middleIsOk:
            result.state = False
            result.info = f"找内板失败,找到的中缝位置不对,太靠近物料边缘 offset = {yOffset}"
            return result
        useImage = boardColor.copy()
        cv.drawContours(useImage,
                        [np.array([leftTop, rightTop, rightBottom, leftBottom])], -1,
                        colorGreen, 3)
        if sizeByExtend:
            image_show("InnerBoardFindedByExtend", useImage)
        else:
            image_show("InnerBoardFindedByCalc", useImage)
        result.box = [leftTop, rightTop, rightBottom, leftBottom]
        widthFinded = round(get_two_point_distance(leftTop, rightTop) / cp.mm2pix, 2)
        heightFinded = round(get_two_point_distance(leftTop, leftBottom) / cp.mm2pix, 2)
        result.calcSize = (widthFinded, heightFinded)
        result.calcError = (round(widthFinded - widthMm, 2), round(heightFinded - heightMm, 2))

        if widthFinded < widthMin or heightFinded < heightMin:
            result.state = False
            result.errorFlag = CheckErrorFlag.Small
            if widthFinded < widthMin:
                result.info = (f"宽度识别尺寸尺寸偏小,识别尺寸: {result.calcSize},"
                               f"识别误差:{result.calcError}")
            else:
                result.info = (f"高度识别尺寸尺寸偏小,识别尺寸: {result.calcSize},"
                               f"识别误差:{result.calcError}")
            return result

        if widthFinded > widthMax or heightFinded > heightMax:
            result.state = False
            result.errorFlag = CheckErrorFlag.Big
            if widthFinded > widthMax:
                result.info = (f"宽度识别偏大,识别尺寸: {result.calcSize},"
                               f"识别误差:{result.calcError}")
            else:
                result.info = (f"高度识别偏大,识别尺寸: {result.calcSize},"
                               f"识别误差:{result.calcError}")
            return result
        result.state = True
        if sizeByExtend:
            result.info = "okByExtend"
        result.info = "ok"
        return result
    except Exception as e:
        result.info = str(e)
        result.state = False
        return result


def get_inner_board_info_1p(board, jointLine, width, height, totalboardBox,
                            isSizeCheck=False):
    """
    2拼板获取内板信息
    :param board:
    :param jointLine:
    :param width:
    :param height:
    :param totalboardBox:
    :param isSizeCheck:
    :return:
    """
    try:
        boardColor = cv.cvtColor(board, cv.COLOR_GRAY2BGR)
        sizeOkRes = []
        sizeDifRes = []
        # 找到板子的中心
        boardHeight, boardWidth = board.shape[:2]
        boardCenter = int(boardWidth / 2), int(boardHeight / 2)
        cv.circle(boardColor, boardCenter, 5, colorGreen, -1)
        image_show("BoardCenter", boardColor)

        for tryTimes in range(tryBeginIndex, len(calcArgs.keys()) + 1):
            cv.destroyAllWindows()
            (gaussianR, squareR, closeKernal, closeTimes,
             openedTimes, thresOffsetList, scharrRate) = calcArgs.get(str(tryTimes))
            print(f"第 {tryTimes}次计算,计算参数: {calcArgs.get(str(tryTimes))}")
            if len(gaussianR) == 1:
                if gaussianR[0] == 0:
                    blurred = board.copy()
                else:
                    blurred = cv.GaussianBlur(board, (0, 0), gaussianR[0])
            else:
                d, colorSigma = gaussianR
                spaceSigma = int(d / 2)
                blurred = cv.bilateralFilter(board, d, colorSigma, spaceSigma)

            if scharrRate == 0:
                scharrXY = blurred.copy()
            else:
                scharrX = cv.Scharr(blurred, cv.CV_64F, 1, 0)
                scharrY = cv.Scharr(blurred, cv.CV_64F, 0, 1)
                scharrX = cv.convertScaleAbs(scharrX)
                scharrY = cv.convertScaleAbs(scharrY)
                scharrXY = cv.addWeighted(scharrX, scharrRate, scharrY, scharrRate, 0)
                scharrXY = cv.convertScaleAbs(scharrXY)
                scharrXY = cv.bitwise_and(scharrXY, jointLine)
            image_show("ScharrXY", scharrXY)
            img32 = np.float32(scharrXY)
            square1 = cv.blur(np.multiply(img32, img32), (squareR, squareR))
            square2 = np.multiply(cv.blur(img32, (squareR, squareR)),
                                  cv.blur(img32, (squareR, squareR)))
            squareDif32 = np.subtract(square1, square2)
            squareDif = squareDif32.copy()
            np.clip(squareDif32, 0, 255, out=squareDif)
            squareDif = squareDif.astype("uint8")
            image_show("SquareDif", squareDif)
            kernelUsed = cv.getStructuringElement(cv.MORPH_RECT, (closeKernal, closeKernal))
            # 进行闭操作,将白色的区域联通
            contourImg = cv.morphologyEx(squareDif, cv.MORPH_CLOSE, kernelUsed,
                                         iterations=closeTimes)
            image_show("squareDifClosed", contourImg)
            squareDifClosed = contourImg.copy()
            for index, thresOffset in enumerate(thresOffsetList):
                cv.destroyAllWindows()
                image_show("ThresBefore", squareDifClosed)
                # 根据阈值分割
                print(f"第 {index + 1} 个阈值 = {thresOffset},进行阈值分割")
                _, contourImg = cv.threshold(squareDifClosed, thresOffset, 255,
                                             cv.THRESH_BINARY_INV)
                image_show(f"BoardThres_({thresOffset})", contourImg)
                if scharrRate == 0:
                    contourImg = cv.bitwise_or(contourImg, cv.bitwise_not(jointLine))
                    image_show("SubtractImage", contourImg)

                #     # 4. 进行泛洪填充,要考虑一种情况是,填充选择的点刚好不是黑点,是个白点的情况.要重新再选一次
                mask = np.zeros((contourImg.shape[0] + 2, contourImg.shape[1] + 2), dtype=np.uint8)
                if contourImg[contourImg.shape[0] // 2, contourImg.shape[1] // 2] != 255:
                    cv.floodFill(contourImg, mask, (int(contourImg.shape[1] * 0.7),
                                                    int(contourImg.shape[0] * 0.7)), colorWhite)
                else:
                    cv.floodFill(contourImg, mask, (contourImg.shape[1] // 2,
                                                    contourImg.shape[0] // 2), colorWhite)

                image_show("FloodFill", contourImg)
                floodFillOpened = cv.morphologyEx(contourImg, cv.MORPH_OPEN, kernelUsed,
                                                  iterations=openedTimes)
                image_show("FloodFillOpened", floodFillOpened)
                res: CheckResult = check_inner_board_1p(floodFillOpened, width, height, boardColor,
                                                        totalboardBox, tryTimes)
                print(f"计算结果: {res.state},{res.info},识别尺寸:{res.calcSize},"
                      f"({int(res.calcSize[0] * cp.mm2pix)},{int(res.calcSize[1] * cp.mm2pix)}),"
                      f"识别误差: {res.calcError}")
                if res.state:
                    if res.info == "ok":
                        sizeOkRes.append(res)
                        calcSize = res.calcSize
                        calcError = res.calcError
                        if get_sum_abs(calcError) < 8 and not isSizeCheck:
                            print(f"返回的ok结果是,算子的编号和亮度阈值:({tryTimes},"
                                  f"{thresOffset}),尺寸:{calcSize}"
                                  f"({int(res.calcSize[0] * cp.mm2pix)},{int(res.calcSize[1] * cp.mm2pix)}),"
                                  f"误差:{calcError}")
                            return "ok", res.info, res.box
                    else:
                        sizeOkRes.append(res)
                        sizeOkRes.append(res)
                else:
                    if res.errorFlag == CheckErrorFlag.Big:
                        if isSizeCheck:
                            sizeOkRes.append(res)
                        else:
                            sizeDifRes.append(res)
                            break
                        continue
                    elif res.errorFlag == CheckErrorFlag.Small:
                        if isSizeCheck:
                            sizeOkRes.append(res)
                        else:
                            # 如果识别尺寸过小,就直接返回了
                            sizeDifRes.append(res)
                        continue

        else:
            # 最外层循环都结束之后
            if isSizeCheck:
                sizeList = []
                boxList = []
                if len(sizeOkRes) >= 1:
                    resOkSorted = sorted(sizeOkRes, key=lambda x: get_sum_abs(x.calcError))
                    for res in resOkSorted:
                        sizeList.append(res.calcSize)
                        boxList.append(res.box)
                    return "ok", sizeList, boxList
                else:
                    return "error", "内板寻找失败", None
            else:
                if len(sizeOkRes) >= 1:
                    resOkSorted = sorted(sizeOkRes, key=lambda x: get_sum_abs(x.calcError))
                    res = resOkSorted[0]
                    print(f"返回的ok结果是:尺寸:{res.calcSize},"
                          f"({int(res.calcSize[0] * cp.mm2pix)},{int(res.calcSize[1] * cp.mm2pix)}),"
                          f"误差:{res.calcError}")
                    return "ok", res.info, res.box

                if len(sizeDifRes) >= 1:
                    resDifSortd = sorted(sizeDifRes, key=lambda x: get_sum_abs(x.calcError))
                    res = resDifSortd[0]
                    return "sizeDif", res.info, res.box

                return "error", "找内板失败", None

    except Exception as e:
        return "error", f"in get_inner_board_info_1p() : error:{e}"


def get_size_check_result_1p(image, width, height, totalboard, totalboardBox):
    """
    获取尺寸确认的图片
    :param image:
    :param width:
    :param height:
    :param totalboard:
    :param totalboardBox:
    :return:
    """
    print("in get_size_check_result_1p() ")
    jointlineMask = np.ones_like(image, dtype=np.uint8) * 255
    jointlineMask[:, cp.middleJointPos - jointLineExtend:cp.middleJointPos + jointLineExtend] = 0
    jointlineMaskNoAngle, _ = get_board_without_angle(jointlineMask, totalboardBox)
    cv.destroyAllWindows()
    image_show("Totalboard", totalboard)
    board = totalboard.copy()
    boardColor = cv.cvtColor(board, cv.COLOR_GRAY2BGR)
    jointLine = jointlineMaskNoAngle.copy()
    res, sizes, boxes = get_inner_board_info_1p(board, jointLine, width, height,
                                                totalboardBox, isSizeCheck=True)
    boardResList = []
    boardSizeResList = []
    if res != "error":
        for index, box in enumerate(boxes):
            if box is not None:
                boardRes = boardColor.copy()
                cv.drawContours(boardRes, [np.array(box)], -1, colorGreen, 3)
                centerX, centerY = board.shape[1] // 2, board.shape[0] // 2
                cv.putText(boardRes, "{}".format(index + 1), (centerX - 8, centerY),
                           cv.FONT_HERSHEY_COMPLEX, 10, colorBlue, 5)
                image_show("boardRes", boardRes)
                boardResList.append(boardRes)
                boardSizeResList.append(sizes[index])
        return "ok", boardSizeResList, boardResList, boardColor
    else:
        return "error", "内板识别出错", None, boardColor


def get_boxes_1p(image, width, height, totalboardBox, totalboard):
    print("in get_boxes_1p() ")
    jointlineMask = np.ones_like(image, dtype=np.uint8) * 255
    jointlineMask[:, cp.middleJointPos - jointLineExtend:cp.middleJointPos + jointLineExtend] = 0
    jointlineMaskNoAngle, _ = get_board_without_angle(jointlineMask, totalboardBox)
    cv.destroyAllWindows()
    image_show("Totalboard", totalboard)
    res1, info1, upLeftBox = get_inner_board_info_1p(totalboard, jointlineMaskNoAngle, width,
                                                     height, totalboardBox)
    if res1 != "ok":
        return False, f"识别失败,识别信息:{info1}", upLeftBox

    totalBoardColor = cv.cvtColor(totalboard.copy(), cv.COLOR_GRAY2BGR)
    drawCnt = [np.array(upLeftBox)]
    cv.drawContours(totalBoardColor, drawCnt, -1, (0, 255, 0), 3)
    image_show("Boxes", totalBoardColor)
    return True, "内框识别成功!", upLeftBox


def get_cutlines_1p(image, totalboardBox, box,
                    totalboardOffset, edgeList) -> CutlineResult:
    """
    根据两个框,去获取切线
    :param image:
    :param totalboardBox:
    :param box:
    :param totalboardOffset:
    :param edgeList: 留边宽度列表
    :return:
    """
    result = CutlineResult()
    boardCenter, (w, h), rotatedAngle = totalboardBox
    M = cv.getRotationMatrix2D(boardCenter, -rotatedAngle, 1)
    boardPoints = [(0, 0), (w, 0), (w, h), (0, h)]  # 顺时针四个点
    boxInBig = [transform_point_to_big(p, M, totalboardOffset) for p in box]
    boardPointsBig = [transform_point_to_big(p, M, totalboardOffset) for p in boardPoints]

    # 调试的时候才会使用
    imageColor = cv.cvtColor(image, cv.COLOR_GRAY2BGR)
    # cntDraw = np.array(boardPointsBig)
    cnt1 = np.array(boxInBig)
    cv.drawContours(imageColor, [cnt1], -1,
                    colorGreen, 3)
    image_show("Boardinfo", imageColor)

    # 然后根据这些信息去获取切线图
    leftTop, rightTop, rightBottom, leftBottom = boxInBig
    # 获取内框的宽和高
    calcWidth = get_two_point_distance(leftTop, rightTop)
    calcHeight = get_two_point_distance(leftTop, leftBottom)
    boardLeftTop, boardRightTop, boardRightBottom, boardLeftBottom = boardPointsBig
    leftCutLineK = get_line_k_and_b(leftTop, leftBottom)[0]
    firstEdge, secondEdge, thirdEdge, fourthEdge = edgeList

    if fourthEdge != 0:
        result.isFourthCut = True
        if leftCutLineK is None:
            leftCutLineB = min(leftTop[0], leftBottom[0]) - fourthEdge
        else:
            leftTopB = leftTop[1] - (leftTop[0] - fourthEdge) * leftCutLineK
            leftBottomB = leftBottom[1] - (leftBottom[0] - fourthEdge) * leftCutLineK
            if leftCutLineK > 0:
                leftCutLineB = max(leftTopB, leftBottomB)
            else:
                leftCutLineB = min(leftTopB, leftBottomB)
    else:
        leftCutLineK, leftCutLineB = get_line_k_and_b(boardLeftTop, boardLeftBottom)

    rightCutLineK = get_line_k_and_b(rightTop, rightBottom)[0]
    if secondEdge != 0:
        result.isSecondCut = True
        if rightCutLineK is None:
            rightCutLineB = max(rightTop[0], rightBottom[0]) + secondEdge
        else:
            rightTopB = rightTop[1] - (rightTop[0] + secondEdge) * rightCutLineK
            rightBottomB = rightBottom[1] - (rightBottom[0] + secondEdge) * rightCutLineK

            if rightCutLineK > 0:
                rightCutLineB = min(rightTopB, rightBottomB)
            else:
                rightCutLineB = max(rightTopB, rightBottomB)
    else:
        rightCutLineK, rightCutLineB = get_line_k_and_b(boardRightTop, boardRightBottom)

    if firstEdge != 0:
        result.isFirstCut = True
        topCutLineK = get_line_k_and_b(leftTop, rightTop)[0]
        topCutLineB = (leftTop[1] - firstEdge) - topCutLineK * leftTop[0]
    else:
        topCutLineK, topCutLineB = get_line_k_and_b(boardLeftTop, boardRightTop)

    if thirdEdge != 0:
        result.isThirdCut = True
        bottomCutLineK = get_line_k_and_b(leftBottom, rightBottom)[0]
        bottomCutLineB = leftBottom[1] + thirdEdge - bottomCutLineK * leftBottom[0]
    else:
        bottomCutLineK, bottomCutLineB = get_line_k_and_b(boardLeftBottom, boardRightBottom)

    leftTopCross = get_two_lines_intersection(topCutLineK, topCutLineB,
                                              leftCutLineK, leftCutLineB)
    rightTopCross = get_two_lines_intersection(topCutLineK,
                                               topCutLineB, rightCutLineK, rightCutLineB)
    leftBottomCross = get_two_lines_intersection(leftCutLineK, leftCutLineB,
                                                 bottomCutLineK, bottomCutLineB)
    rightBottomCross = get_two_lines_intersection(rightCutLineK, rightCutLineB,
                                                  bottomCutLineK, bottomCutLineB)

    cutWidth = get_two_point_distance(leftTopCross, rightTopCross)
    cutHeight = get_two_point_distance(leftTopCross, leftBottomCross)

    # 获取中心点,两个对角线中心点坐标
    centerPoint1 = get_two_points_middle(leftTopCross, rightBottomCross)
    centerPoint2 = get_two_points_middle(leftBottomCross, rightTopCross)
    print(f"中心点坐标p1 = {centerPoint1},p2 = {centerPoint2},"
          f"偏差:{get_two_point_distance(centerPoint1, centerPoint2)}")

    # 获取第一边和标定点之间的角度

    angle = get_two_line_angle((leftTopCross, rightTopCross),
                               (rp.imageP1, rp.imageP2))
    print(f"第一边角度:{angle}")
    cv.line(imageColor, (int(leftTopCross[0]), int(leftTopCross[1])),
            (int(rightTopCross[0]), int(rightTopCross[1])), colorRed, 3)
    cv.putText(imageColor, '1', (int((leftTopCross[0] + rightTopCross[0]) / 2),
                                 int((rightTopCross[1] + leftTopCross[1]) / 2) + 100),
               cv.FONT_HERSHEY_COMPLEX, 4, colorRed, 5)
    cv.line(imageColor, (int(leftBottomCross[0]), int(leftBottomCross[1])),
            (int(rightBottomCross[0]), int(rightBottomCross[1])), colorRed, 3)
    cv.putText(imageColor, '3', (int((leftBottomCross[0] + rightBottomCross[0]) / 2),
                                 int((leftBottomCross[1] + rightBottomCross[1]) / 2) - 100),
               cv.FONT_HERSHEY_COMPLEX, 4, colorRed, 5)

    cv.line(imageColor, (int(rightTopCross[0]), int(rightTopCross[1])),
            (int(rightBottomCross[0]), int(rightBottomCross[1])), colorRed, 3)
    cv.putText(imageColor, '2', (int((rightTopCross[0] + rightBottomCross[0]) / 2) - 100,
                                 int((rightTopCross[1] + rightBottomCross[1]) / 2)),
               cv.FONT_HERSHEY_COMPLEX, 4, colorRed, 5)
    cv.line(imageColor, (int(leftTopCross[0]), int(leftTopCross[1])),
            (int(leftBottomCross[0]), int(leftBottomCross[1])), colorRed, 3)
    cv.putText(imageColor, '4', (int((leftBottomCross[0] + leftTopCross[0]) / 2) + 30,
                                 int((leftTopCross[1] + leftBottomCross[1]) / 2)),
               cv.FONT_HERSHEY_COMPLEX, 4, colorRed, 5)

    imageResult, _ = get_board_without_angle(imageColor, totalboardBox, extend=80)
    image_show("ResultImage", imageResult)

    robotPos1, robotPos2 = get_robot_pos(angle, centerPoint1)
    result.robotX01 = round(robotPos1[0], 2)
    result.robotY01 = round(robotPos1[1], 2)
    result.robotR01 = round(robotPos1[2], 2)
    result.robotX02 = round(robotPos2[0], 2)
    result.robotY02 = round(robotPos2[1], 2)
    result.robotR02 = round(robotPos2[2], 2)
    result.cutLen = round(cutHeight / cp.mm2pix, 2)  # 长度,垂直于相机,相当于是宽度
    result.cutWidth = round(cutWidth / cp.mm2pix, 2)  # 宽度,平行于相机,相当于是高度
    result.state = True
    result.imgRes = imageResult
    result.calcWidth = round(calcWidth / cp.mm2pix, 2)
    result.calcHeight = round(calcHeight / cp.mm2pix, 2)
    result.pack_info()

    if result.cutLen < 300:
        result.state = False
        result.info = "切割后长度(垂直于相机支架)小于300,请确认切线是否正确"
        return result
    if result.cutWidth < 300:
        result.state = False
        result.info = "切割后宽度(平行于相机支架)小于300,请确认切线是否正确"
    return result


if __name__ == '__main__':
    # filePath = os.path.join(app_config.baseDir, r"raw_test")
    filePath = r"F:\raw_2025\fangzheng_1p"
    isFirstBoard = False
    edgeList = [15, 15, 15, 15]
    edgePixList = [int(edge * cp.mm2pix) for edge in edgeList]

    keepDir = filePath
    if not os.path.isdir(keepDir):
        keepDir, _ = os.path.split(filePath)

    keepOkPath = os.path.join(keepDir, "ok")
    keepOkResPath = os.path.join(keepDir, "cutlines")
    keepFailPath = os.path.join(keepDir, "fail")
    keepFirstSizeBestRes = os.path.join(keepDir, "first_size_check_best")

    dirList = [keepOkPath, keepOkResPath, keepFailPath, keepFirstSizeBestRes]
    for dirDemo in dirList:
        if not os.path.exists(dirDemo):
            os.makedirs(dirDemo)

    fileNames = []
    for root, dirs, files in os.walk(keepDir):
        if root != keepDir:
            continue
        for file in files:
            if not file.endswith(".bmp"):
                continue
            fileNames.append(file)

    for indexFile, fileName in enumerate(fileNames, start=1):
        filePathReal = os.path.join(keepDir, fileName)
        srcW, srcH = get_width_height_by_image_name(fileName)
        if not (srcW and srcH):
            print(f"{'*' * 10} 第 {indexFile} 张图 ({fileName}),图像读取错误,已跳过. {'*' * 10}")
            continue
        imageSrc = cv.imread(filePathReal, cv.IMREAD_GRAYSCALE)
        # imageSrc = rotate_image(imageSrc, -3)
        if imageSrc is None:
            print(f"{'*' * 10} 第 {indexFile} 张图 ({fileName}),图像读取错误,已跳过. {'*' * 10}")
        else:
            print(f"{'*' * 10} 第 {indexFile} 张图 ({fileName}),开始识别 {'*' * 10}")
        calcStart = time.time()

        calc_config.showState = False
        resultTest: TotalboardResult = check_totalboard_is_ok(imageSrc)
        print(resultTest.info)
        totalboardBoxOuter = resultTest.boxMaster
        totalboardOuter = resultTest.totalboardGray
        totalboardOffset = resultTest.totalboardOffset
        calc_config.showState = False
        if isFirstBoard:
            resFirst, boardSizeList, boardResList, upLeftBoard = get_size_check_result_1p(
                imageSrc, srcW, srcH, totalboardOuter, totalboardBoxOuter)
            if resFirst != "error":
                sizeCheckResBest = boardResList[0]
                sizeCheckResBest = get_size_scale_image(sizeCheckResBest, sizeScale=4)
                cv.imwrite(os.path.join(keepFirstSizeBestRes, fileName), sizeCheckResBest)
        res, info, box1p = get_boxes_1p(imageSrc, srcW, srcH, totalboardBoxOuter,
                                        totalboardOuter)
        if res:
            calc_config.showState = False
            lineResult = get_cutlines_1p(imageSrc, totalboardBoxOuter, box1p,
                                         totalboardOffset, edgePixList)
        else:
            lineResult = None
        if res and lineResult.state:
            print(f"分割线查找成功,算法耗时: {(time.time() - calcStart):.4f}")
            print(lineResult.info)
            os.remove(filePathReal)
            cv.imwrite(os.path.join(keepOkPath, fileName), imageSrc)
            imageRes = get_size_scale_image(lineResult.imgRes, sizeScale=3)
            cv.imwrite(os.path.join(keepOkResPath, fileName), imageRes)
        else:
            print(f"分割线查找失败XXXX,原因: {res},算法耗时: {(time.time() - calcStart):.4f}")
            cv.imwrite(os.path.join(keepFailPath, fileName), imageSrc)
            os.remove(filePathReal)
